/*
 * timer_functions.c
 *
 * Created: 29.03.2013 12:11:21
 *  Author: Timmo
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>

#include "signal.h"		//needed for status LED blinking
#include "timer_functions.h"
volatile uint16_t rtc_seconds;
volatile uint16_t ms_counter;
volatile uint16_t display_standby_timer;

volatile uint8_t function_is_active=0;

// we try to keep the last time in RAM
time_t t __attribute__((section(".noinit")));

extern uint8_t display_standbystate;	// declared in SSD1306.c

char not_leap(void)      //check for leap year
{
	if (!(t.year%100))
	return (char)(t.year%400);
	else
	return (char)(t.year%4);
}

void init_short_time_counter(){
	TCD0.CNT = 0;
	TCD0.PER = 499;
	TCD0.CTRLA = TC_CLKSEL_DIV8_gc;
	TCD0.INTCTRLA = TC_OVFINTLVL_LO_gc;	// Low Level Interrupt
}

void waitms(uint16_t ms){
	cli();
	ms_counter=0;
	sei();
	TCD0.CNT = 0;
	while(ms_counter < ms);
}

void stop_short_time_counter(){
	TCD0.CTRLA = 0; //Stop timer	
	TCD0.INTCTRLA &= ~TC_OVFINTLVL_LO_gc;	// Low Level Interrupt
}

void init_RTC(){

	
	CLK.RTCCTRL = CLK_RTCSRC_RCOSC_gc | CLK_RTCEN_bm;
	RTC.CTRL |= RTC_PRESCALER_DIV1_gc;
	while( RTC.STATUS & RTC_SYNCBUSY_bm); //Wait RTC Busy
	RTC.PER = 1024-1; //1s
	RTC.CNT = 0;
	RTC.COMP = 0;
	RTC.INTCTRL |= RTC_OVFINTLVL_LO_gc;
	
}

void reset_display_standbytimer(){
	cli();
	display_standby_timer = 0;
	sei();
}
	
void RTC_reset_timer(){
	//reset atomic
	cli();
	rtc_seconds = 0;
	sei();
	RTC.CNT = 0;
}

ISR(RTC_OVF_vect){
	static uint8_t led_counter=0;
	
	rtc_seconds++;
	display_standby_timer++;
	//if LED is off, start blinking
	if(display_standbystate == 1){
		led_counter++;
		// we activate the compare interrupt every "STATUS_LED_PERIOD"
		if(led_counter > STATUS_LED_PERIOD - 1){
			LED_ON();
			led_counter = 0;
			RTC.INTCTRL |= RTC_COMPINTLVL_LO_gc;
			RTC.INTFLAGS |= RTC_COMPIF_bm;
			RTC.COMP = 50; //~50ms LED on-time
			
		}

	}
	
	if (++t.second==60)        //keep track of time, date, month, and year
	{
		t.second=0;
		if (++t.minute==60)
		{
			t.minute=0;
			if (++t.hour==24)
			{
				t.hour=0;
				if (++t.date==32)
				{
					t.month++;
					t.date=1;
				}
				else if (t.date==31)
				{
					if ((t.month==4) || (t.month==6) || (t.month==9) || (t.month==11))
					{
						t.month++;
						t.date=1;
					}
				}
				else if (t.date==30)
				{
					if(t.month==2)
					{
						t.month++;
						t.date=1;
					}
				}
				else if (t.date==29)
				{
					if((t.month==2) && (not_leap()))
					{
						t.month++;
						t.date=1;
					}
				}
				if (t.month==13)
				{
					t.month=1;
					t.year++;
				}
			}
		}
	}
}

ISR(RTC_COMP_vect){
	static uint8_t led_blink_state=0;
	
	// if any function is active (Intervall, Long exp....)
	// we do a double blink of the LED as indicator
	if(function_is_active){
		switch(led_blink_state){
			case 0:
				LED_OFF();
				RTC.COMP = 100;
				led_blink_state++;
				break;
			case 1:
				LED_ON();
				RTC.COMP = 150;
				led_blink_state++;
				break;
			case 2:
				LED_OFF();
				RTC.INTCTRL &= ~RTC_COMPINTLVL_LO_gc;
				led_blink_state=0;
		}		
	}
	else{
		LED_OFF();
		RTC.INTCTRL &= ~RTC_COMPINTLVL_LO_gc;
		
	}	
	
}

ISR(TCD0_OVF_vect){
	ms_counter++;			
}	